home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / tk2.3 / dist / tkGC.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-13  |  8.7 KB  |  328 lines

  1. /* 
  2.  * tkGC.c --
  3.  *
  4.  *    This file maintains a database of read-only graphics contexts 
  5.  *    for the Tk toolkit, in order to allow GC's to be shared.
  6.  *
  7.  * Copyright 1990 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkGC.c,v 1.9 92/05/13 08:48:45 ouster Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include "tkConfig.h"
  22. #include "tk.h"
  23.  
  24. /*
  25.  * One of the following data structures exists for each GC that is
  26.  * currently active.  The structure is indexed with two hash tables,
  27.  * one based on font name and one based on XFontStruct address.
  28.  */
  29.  
  30. typedef struct {
  31.     GC gc;            /* Graphics context. */
  32.     Display *display;        /* Display to which gc belongs. */
  33.     int refCount;        /* Number of active uses of gc. */
  34.     Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting
  35.                  * this structure). */
  36. } TkGC;
  37.  
  38. /*
  39.  * Hash table to map from a GC's values to a TkGC structure describing
  40.  * a GC with those values (used by Tk_GetGC).
  41.  */
  42.  
  43. static Tcl_HashTable valueTable;
  44. typedef struct {
  45.     XGCValues values;        /* Desired values for GC. */
  46.     Display *display;        /* Display for which GC is valid. */
  47. } ValueKey;
  48.  
  49. /*
  50.  * Hash table for GC -> TkGC mapping. This table is indexed by the 
  51.  * GC identifier, and is used by Tk_FreeGC.
  52.  */
  53.  
  54. static Tcl_HashTable idTable;
  55.  
  56. static int initialized = 0;    /* 0 means static structures haven't been
  57.                  * initialized yet. */
  58.  
  59. /*
  60.  * Forward declarations for procedures defined in this file:
  61.  */
  62.  
  63. static void        GCInit _ANSI_ARGS_((void));
  64.  
  65. /*
  66.  *----------------------------------------------------------------------
  67.  *
  68.  * Tk_GetGC --
  69.  *
  70.  *    Given a desired set of values for a graphics context, find
  71.  *    a read-only graphics context with the desired values.
  72.  *
  73.  * Results:
  74.  *    The return value is the X identifer for the desired graphics
  75.  *    context.  The caller should never modify this GC, and should
  76.  *    call Tk_FreeGC when the GC is no longer needed.
  77.  *
  78.  * Side effects:
  79.  *    The GC is added to an internal database with a reference count.
  80.  *    For each call to this procedure, there should eventually be a call
  81.  *    to Tk_FreeGC, so that the database can be cleaned up when GC's
  82.  *    aren't needed anymore.
  83.  *
  84.  *----------------------------------------------------------------------
  85.  */
  86.  
  87. GC
  88. Tk_GetGC(tkwin, valueMask, valuePtr)
  89.     Tk_Window tkwin;        /* Window in which GC will be used. */
  90.     register unsigned long valueMask;
  91.                 /* 1 bits correspond to values specified
  92.                  * in *valuesPtr;  other values are set
  93.                  * from defaults. */
  94.     register XGCValues *valuePtr;
  95.                 /* Values are specified here for bits set
  96.                  * in valueMask. */
  97. {
  98.     ValueKey key;
  99.     Tcl_HashEntry *valueHashPtr, *idHashPtr;
  100.     register TkGC *gcPtr;
  101.     int new;
  102.  
  103.     if (!initialized) {
  104.     GCInit();
  105.     }
  106.  
  107.     /*
  108.      * Must zero key at start to clear out pad bytes that may be
  109.      * part of structure on some systems.
  110.      */
  111.  
  112.     memset((VOID *) &key, 0, sizeof(key));
  113.  
  114.     /*
  115.      * First, check to see if there's already a GC that will work
  116.      * for this request (exact matches only, sorry).
  117.      */
  118.  
  119.     if (valueMask & GCFunction) {
  120.     key.values.function = valuePtr->function;
  121.     } else {
  122.     key.values.function = GXcopy;
  123.     }
  124.     if (valueMask & GCPlaneMask) {
  125.     key.values.plane_mask = valuePtr->plane_mask;
  126.     } else {
  127.     key.values.plane_mask = ~0;
  128.     }
  129.     if (valueMask & GCForeground) {
  130.     key.values.foreground = valuePtr->foreground;
  131.     } else {
  132.     key.values.foreground = 0;
  133.     }
  134.     if (valueMask & GCBackground) {
  135.     key.values.background = valuePtr->background;
  136.     } else {
  137.     key.values.background = 1;
  138.     }
  139.     if (valueMask & GCLineWidth) {
  140.     key.values.line_width = valuePtr->line_width;
  141.     } else {
  142.     key.values.line_width = 0;
  143.     }
  144.     if (valueMask & GCLineStyle) {
  145.     key.values.line_style = valuePtr->line_style;
  146.     } else {
  147.     key.values.line_style = LineSolid;
  148.     }
  149.     if (valueMask & GCCapStyle) {
  150.     key.values.cap_style = valuePtr->cap_style;
  151.     } else {
  152.     key.values.cap_style = CapButt;
  153.     }
  154.     if (valueMask & GCJoinStyle) {
  155.     key.values.join_style = valuePtr->join_style;
  156.     } else {
  157.     key.values.join_style = JoinMiter;
  158.     }
  159.     if (valueMask & GCFillStyle) {
  160.     key.values.fill_style = valuePtr->fill_style;
  161.     } else {
  162.     key.values.fill_style = FillSolid;
  163.     }
  164.     if (valueMask & GCFillRule) {
  165.     key.values.fill_rule = valuePtr->fill_rule;
  166.     } else {
  167.     key.values.fill_rule = EvenOddRule;
  168.     }
  169.     if (valueMask & GCArcMode) {
  170.     key.values.arc_mode = valuePtr->arc_mode;
  171.     } else {
  172.     key.values.arc_mode = ArcPieSlice;
  173.     }
  174.     if (valueMask & GCTile) {
  175.     key.values.tile = valuePtr->tile;
  176.     } else {
  177.     key.values.tile = None;
  178.     }
  179.     if (valueMask & GCStipple) {
  180.     key.values.stipple = valuePtr->stipple;
  181.     } else {
  182.     key.values.stipple = None;
  183.     }
  184.     if (valueMask & GCTileStipXOrigin) {
  185.     key.values.ts_x_origin = valuePtr->ts_x_origin;
  186.     } else {
  187.     key.values.ts_x_origin = 0;
  188.     }
  189.     if (valueMask & GCTileStipYOrigin) {
  190.     key.values.ts_y_origin = valuePtr->ts_y_origin;
  191.     } else {
  192.     key.values.ts_y_origin = 0;
  193.     }
  194.     if (valueMask & GCFont) {
  195.     key.values.font = valuePtr->font;
  196.     } else {
  197.     key.values.font = None;
  198.     }
  199.     if (valueMask & GCSubwindowMode) {
  200.     key.values.subwindow_mode = valuePtr->subwindow_mode;
  201.     } else {
  202.     key.values.subwindow_mode = ClipByChildren;
  203.     }
  204.     if (valueMask & GCGraphicsExposures) {
  205.     key.values.graphics_exposures = valuePtr->graphics_exposures;
  206.     } else {
  207.     key.values.graphics_exposures = True;
  208.     }
  209.     if (valueMask & GCClipXOrigin) {
  210.     key.values.clip_x_origin = valuePtr->clip_x_origin;
  211.     } else {
  212.     key.values.clip_x_origin = 0;
  213.     }
  214.     if (valueMask & GCClipYOrigin) {
  215.     key.values.clip_y_origin = valuePtr->clip_y_origin;
  216.     } else {
  217.     key.values.clip_y_origin = 0;
  218.     }
  219.     if (valueMask & GCClipMask) {
  220.     key.values.clip_mask = valuePtr->clip_mask;
  221.     } else {
  222.     key.values.clip_mask = None;
  223.     }
  224.     if (valueMask & GCDashOffset) {
  225.     key.values.dash_offset = valuePtr->dash_offset;
  226.     } else {
  227.     key.values.dash_offset = 0;
  228.     }
  229.     if (valueMask & GCDashList) {
  230.     key.values.dashes = valuePtr->dashes;
  231.     } else {
  232.     key.values.dashes = 4;
  233.     }
  234.     key.display = Tk_Display(tkwin);
  235.     valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &key, &new);
  236.     if (!new) {
  237.     gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr);
  238.     gcPtr->refCount++;
  239.     return gcPtr->gc;
  240.     }
  241.  
  242.     /*
  243.      * No GC is currently available for this set of values.  Allocate a
  244.      * new GC and add a new structure to the database.
  245.      */
  246.  
  247.     gcPtr = (TkGC *) ckalloc(sizeof(TkGC));
  248.     gcPtr->gc = XCreateGC(key.display, RootWindowOfScreen(Tk_Screen(tkwin)),
  249.         valueMask, &key.values);
  250.     gcPtr->display = key.display;
  251.     gcPtr->refCount = 1;
  252.     gcPtr->valueHashPtr = valueHashPtr;
  253.     idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) gcPtr->gc, &new);
  254.     if (!new) {
  255.     panic("GC already registered in Tk_GetGC");
  256.     }
  257.     Tcl_SetHashValue(valueHashPtr, gcPtr);
  258.     Tcl_SetHashValue(idHashPtr, gcPtr);
  259.     return gcPtr->gc;
  260. }
  261.  
  262. /*
  263.  *----------------------------------------------------------------------
  264.  *
  265.  * Tk_FreeGC --
  266.  *
  267.  *    This procedure is called to release a font allocated by
  268.  *    Tk_GetGC.
  269.  *
  270.  * Results:
  271.  *    None.
  272.  *
  273.  * Side effects:
  274.  *    The reference count associated with gc is decremented, and
  275.  *    gc is officially deallocated if no-one is using it anymore.
  276.  *
  277.  *----------------------------------------------------------------------
  278.  */
  279.  
  280. void
  281. Tk_FreeGC(gc)
  282.     GC gc;            /* Graphics context to be released. */
  283. {
  284.     Tcl_HashEntry *idHashPtr;
  285.     register TkGC *gcPtr;
  286.  
  287.     if (!initialized) {
  288.     panic("Tk_FreeGC called before Tk_GetGC");
  289.     }
  290.  
  291.     idHashPtr = Tcl_FindHashEntry(&idTable, (char *) gc);
  292.     if (idHashPtr == NULL) {
  293.     panic("Tk_FreeGC received unknown gc argument");
  294.     }
  295.     gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr);
  296.     gcPtr->refCount--;
  297.     if (gcPtr->refCount == 0) {
  298.     XFreeGC(gcPtr->display, gcPtr->gc);
  299.     Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
  300.     Tcl_DeleteHashEntry(idHashPtr);
  301.     ckfree((char *) gcPtr);
  302.     }
  303. }
  304.  
  305. /*
  306.  *----------------------------------------------------------------------
  307.  *
  308.  * GCInit --
  309.  *
  310.  *    Initialize the structures used for GC management.
  311.  *
  312.  * Results:
  313.  *    None.
  314.  *
  315.  * Side effects:
  316.  *    Read the code.
  317.  *
  318.  *----------------------------------------------------------------------
  319.  */
  320.  
  321. static void
  322. GCInit()
  323. {
  324.     initialized = 1;
  325.     Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
  326.     Tcl_InitHashTable(&idTable, TCL_ONE_WORD_KEYS);
  327. }
  328.